package com.aispeech.asr.apis.ssc.beans;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.aispeech.asr.apis.ssc.config.AppConfig;
import com.aispeech.asr.apis.ssc.constants.Progress;
import com.aispeech.asr.apis.ssc.data.domain.AudioInfo;
import com.aispeech.asr.apis.ssc.data.domain.TaskDoc;
import com.aispeech.asr.apis.ssc.event.SscEvent;
import com.aispeech.asr.apis.ssc.service.ProgressManager;
import com.aispeech.asr.comm.enums.ErrorCode;
import com.aispeech.asr.comm.exceptions.AsrException;
import com.aispeech.asr.comm.utils.FileUtils;
import com.aispeech.asr.comm.utils.ShellUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;


@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Paragrapher implements Function<SscEvent, SscEvent> {
    private String DIR;
    private static final String CMD = "./paragraph";

    @Autowired
    AppConfig config;
    @Autowired
    ProgressManager progressManager;

    @SneakyThrows
    @Override
    public SscEvent apply(SscEvent event) {
    	
        TaskDoc taskDoc = event.getTaskDoc();
        log.info("[ Paragrapher ] start。。。taskId:{}",taskDoc.getId());
        
        AudioInfo audioInfo = event.getAudioInfo();
        
        if (taskDoc.getProgress() >= Progress.PARAGRAPHED) {
            return event;
        }

        progressManager.syncToMongo(taskDoc, Progress.PARAGRAPHING);
        taskDoc.addMetric("paragraph_t");
        
        beginParagraph(audioInfo,taskDoc);
        
        progressManager.syncToMongo(taskDoc, Progress.PARAGRAPHED);
        taskDoc.addMetric("paragraphed_t");
        
        log.info("[ Paragrapher ] end。。。taskId:{}",taskDoc.getId());
        
        return event;
    }
    
    private void beginParagraph(AudioInfo audioInfo,TaskDoc taskDoc) throws AsrException {
    	
    	String resPath = String.format("%s/%s", config.getResRoot(),config.getParagraphRes());
    	try {
	    	ObjectMapper objectMapper = new ObjectMapper();
	    	String resultStr = objectMapper.writeValueAsString(taskDoc.getResult());
	    	
	    	String jsonPath  = audioInfo.getWorkDir() + "/result.json";
	    	String resultPath  = audioInfo.getWorkDir() + "/paragraph.json";
	    	
	    	Path path = Paths.get(jsonPath);
	    	if (path.toFile().exists()) {
                FileUtils.delete(path, true);
            }
            Files.copy(new ByteArrayInputStream(resultStr.getBytes("UTF-8")), path);
	    	
	        List<String> cmd = Arrays.asList(
	        		CMD,
	        		"-json",
	        		jsonPath,
	        		"-file",
	        		resultPath
	        );
	        log.info("[ {} ] cmd: {}.", "beginParagraph", cmd);
	        
	        Map<String,String> resultMap = new HashMap<String,String>();
	        ShellUtils.exec(resPath, 3,TimeUnit.MINUTES, cmd,resultMap);
	        
	        File resultFile = new File(resultPath);
	        if(!resultFile.exists() ||  (resultFile.exists() && resultFile.length() == 0)) {
	        	throw new AsrException(
	                    ErrorCode.ERR_AUDIO_PARAGRAPH_FAILED.errid,
	                    ""
	            );
	        }
	        
	        String content = org.apache.commons.io.FileUtils.readFileToString(resultFile, "utf-8");
	        if(StringUtils.isBlank(content)) {
	        	throw new AsrException(
	                    ErrorCode.ERR_AUDIO_PARAGRAPH_FAILED.errid,
	                    ""
	            );
	        }
	        JsonNode resultNode = objectMapper.readTree(content);
	        if (resultNode.isArray()){
	        	List<Map<String, Object>> sscVprMapList = new ArrayList<Map<String, Object>>();
	            Iterator<JsonNode> it = resultNode.iterator();
	            while (it.hasNext()){
	            	JsonNode result = it.next();
		    		Map<String, Object> map = new HashMap<String,Object>();
		    		map.put("bg", result.get("bg").asLong());
		    		map.put("ed", result.get("ed").asLong());
		    		map.put("speaker_ssc", result.get("speaker_ssc").asText());
		    		map.put("staff", result.get("staff").asInt());
		    		map.put("speaker", result.get("speaker").asText());
		    		map.put("paragraph", result.get("paragraph").asInt());
		    		sscVprMapList.add(map);
	            }
	            taskDoc.setResult(sscVprMapList);
	        }else {
	        	throw new AsrException(
	                    ErrorCode.ERR_AUDIO_PARAGRAPH_FAILED.errid,
	                    ""
	            );
	        }
        } catch (AsrException | IOException e) {
            throw new AsrException(
                    ErrorCode.ERR_AUDIO_PARAGRAPH_FAILED.errid,
                    e.getMessage()
            );
        }
    }
}
